import axios, {AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig} from 'axios'
import {useUserStore} from '@/store/modules/user'
import {ApiStatus} from './status'
import {HttpError, handleError, showError, showSuccess} from './error'
import {$t} from '@/locales'

/** 请求配置常量 */
const REQUEST_TIMEOUT = 15000
const LOGOUT_DELAY = 500
const MAX_RETRIES = 0
const RETRY_DELAY = 1000
const UNAUTHORIZED_DEBOUNCE_TIME = 3000

/** 401防抖状态 */
let isUnauthorizedErrorShown = false
let unauthorizedTimer: NodeJS.Timeout | null = null

/** 扩展 AxiosRequestConfig */
interface ExtendedAxiosRequestConfig extends AxiosRequestConfig {
	showErrorMessage?: boolean
	showSuccessMessage?: boolean
}

const {VITE_API_URL, VITE_WITH_CREDENTIALS} = import.meta.env

/** Axios实例 */
const axiosInstance = axios.create({
	timeout: REQUEST_TIMEOUT,
	baseURL: VITE_API_URL,
	withCredentials: VITE_WITH_CREDENTIALS === 'true',
	validateStatus: (status) => status >= 200 && status < 300,
	transformResponse: [
		(data, headers) => {
			const contentType = headers['content-type']
			if (contentType?.includes('application/json')) {
				try {
					return JSON.parse(data)
				} catch {
					return data
				}
			}
			return data
		}
	]
})

/** 请求拦截器 */
axiosInstance.interceptors.request.use(
	(request: InternalAxiosRequestConfig) => {
		const {accessToken, language} = useUserStore()
		if (accessToken) request.headers.set('Authorization', accessToken)
		if (language) request.headers.set('Accept-Language', language)

		if (request.data && !(request.data instanceof FormData) && !request.headers['Content-Type']) {
			request.headers.set('Content-Type', 'application/json')
			request.data = JSON.stringify(request.data)
		}

		return request
	},
	(error) => {
		showError(createHttpError($t('httpMsg.requestConfigError'), ApiStatus.error))
		return Promise.reject(error)
	}
)

/** 响应拦截器 */
axiosInstance.interceptors.response.use(
	(response: AxiosResponse<Http.BaseResponse>) => {
		const {code, msg} = response.data
		if (code === ApiStatus.success) return response
		if (code === ApiStatus.unauthorized) handleUnauthorizedError(msg)
		throw createHttpError(msg || $t('httpMsg.requestFailed'), code)
	},
	(error) => {
		if (error.response?.status === ApiStatus.unauthorized) handleUnauthorizedError()
		return Promise.reject(handleError(error))
	}
)

/** 统一创建HttpError */
function createHttpError(message: string, code: number) {
	return new HttpError(message, code)
}

/** 处理401错误（带防抖） */
function handleUnauthorizedError(message?: string): never {
	const error = createHttpError(message || $t('httpMsg.unauthorized'), ApiStatus.unauthorized)

	if (!isUnauthorizedErrorShown) {
		isUnauthorizedErrorShown = true
		logOut()

		unauthorizedTimer = setTimeout(resetUnauthorizedError, UNAUTHORIZED_DEBOUNCE_TIME)

		showError(error, true)
		throw error
	}

	throw error
}

/** 重置401防抖状态 */
function resetUnauthorizedError() {
	isUnauthorizedErrorShown = false
	if (unauthorizedTimer) clearTimeout(unauthorizedTimer)
	unauthorizedTimer = null
}

/** 退出登录函数 */
function logOut() {
	setTimeout(() => {
		useUserStore().logOut()
	}, LOGOUT_DELAY)
}

/** 是否需要重试 */
function shouldRetry(statusCode: number) {
	return [
		ApiStatus.requestTimeout,
		ApiStatus.internalServerError,
		ApiStatus.badGateway,
		ApiStatus.serviceUnavailable,
		ApiStatus.gatewayTimeout
	].includes(statusCode)
}

/** 请求重试逻辑 */
async function retryRequest<T>(
	config: ExtendedAxiosRequestConfig,
	retries: number = MAX_RETRIES
): Promise<T> {
	try {
		return await request<T>(config)
	} catch (error) {
		if (retries > 0 && error instanceof HttpError && shouldRetry(error.code)) {
			await delay(RETRY_DELAY)
			return retryRequest<T>(config, retries - 1)
		}
		throw error
	}
}

/** 延迟函数 */
function delay(ms: number) {
	return new Promise((resolve) => setTimeout(resolve, ms))
}

/** 请求函数 */
async function request<T = any>(config: ExtendedAxiosRequestConfig): Promise<T> {
	// POST | PUT 参数自动填充
	if (
		['POST', 'PUT'].includes(config.method?.toUpperCase() || '') &&
		config.params &&
		!config.data
	) {
		config.data = config.params
		config.params = undefined
	}

	try {
		const res = await axiosInstance.request<Http.BaseResponse<T>>(config)

		// 显示成功消息
		if (config.showSuccessMessage && res.data.msg) {
			showSuccess(res.data.msg)
		}

		return res.data.data as T
	} catch (error) {
		if (error instanceof HttpError && error.code !== ApiStatus.unauthorized) {
			const showMsg = config.showErrorMessage !== false
			showError(error, showMsg)
		}
		return Promise.reject(error)
	}
}

/** API方法集合 */
const api = {
	get<T>(config: ExtendedAxiosRequestConfig) {
		return retryRequest<T>({...config, method: 'GET'})
	},
	post<T>(config: ExtendedAxiosRequestConfig) {
		return retryRequest<T>({...config, method: 'POST'})
	},
	put<T>(config: ExtendedAxiosRequestConfig) {
		return retryRequest<T>({...config, method: 'PUT'})
	},
	del<T>(config: ExtendedAxiosRequestConfig) {
		return retryRequest<T>({...config, method: 'DELETE'})
	},
	request<T>(config: ExtendedAxiosRequestConfig) {
		return retryRequest<T>(config)
	}
}

export default api
